Previous Book Contents Book Index Next

Inside Macintosh: AppleScript Scripting Additions Guide /
Chapter 3 - Writing Scripting Additions



Sample Scripting Addition

Listing 3-3 demonstrates the basic structure of a scripting addition handler and its associated 'aete' resource. It is called "Play Sound Scripting Addition" and is written in MPW C.

Listing 3-3 Play Sound scripting addition
////////////////////////////////////////////////////////////////////
//
// PlaySnd.c 
//  
// The Play Sound Scripting Addition
// Copyright ®1993 Apple Computer Inc. 
// All rights reserved.
// 
// Written by: Donald Olson
//
// To build:
// C -b "PlaySnd.c" -d SystemSevenOrLater 
// Rez -a -o "Play Sound" -t osax -c ascr 'PlaySnd.r'
// Link -p -w -t osax -c ascr -rt osax=1000 -m PLAYSNDENTRY -sg 
//    "AEVTaevtplsn" -ra "AEVTaevtplsn"=resSysHeap,resLocked 
//    "PlaySnd.c.o" 
//    "{CLibraries}"StdCLib.o 
//    "{Libraries}"Runtime.o 
//    "{Libraries}"Interface.o 
//    -o "Play Sound" 
//
////////////////////////////////////////////////////////////////////

#include <Resources.h>#include <Sound.h>#include <AppleEvents.h> 

#define kAsync          true        // asynchronous play
#define kQuietNow       true        // quiet channel now

#define kSndType        'snd '      // resource type we're 
                                    //looking for
#define typeIntlText    'itxt'      // defined in AERegistry.r
#define typeStyledText  'STXT'      // defined in AERegistry.r
//////////////////////////////////////////////////////////////////// 
//
// PlaySndEntry () 
//
// The direct parameter is either a name or an ID of the 'snd '
// resource to play. 
//
//////////////////////////////////////////////////////////////////

pascal OSErr PlaySndEntry( AppleEvent *theAEEvent, 
                           AppleEvent *theReply, 
                           long theRefCon) 

{   
   /* Function Prototypes */
    OSErr PlaySound(Handle theSoundHdl);
    
   /* variables */
   OSErr          theErr = noErr; 
   DescType       typeCode;
   Size           sizeOfParam,
                  actualSize;
   Handle         theSndHandle = nil;  /*just clear our */
                                       /* sound handle*/
   SndChannelPtr  theSndChan = NULL;   /*NULL pointer to */
                                       /* a sound channel*/
   short          ourRezID = 0;
   Str255         ourRezName;
   FSSpec         ourSoundFile;
   short          ourFileRef, curResFile;

   /* 
      Get the data type from direct object by using AESizeOfParam.
      We use this call instead of AEGetParamDesc or AEGetParamPtr
      because we are looking for one of several types. In this
      way we can determine the type and move its data directly
      into a variable instead of an AEDesc. Now we don't have to
      worry about disposing of the AEDesc later.
   */
   
   theErr = AESizeOfParam( theAEEvent,
                           keyDirectObject,
                           &typeCode,
                           &sizeOfParam);
   if(theErr != noErr){    
      /*
         If we fail here, just return the error. We don't need to
         do any cleanup, because we've allocated nothing on the
         heap yet. The Apple Event Manager automatically adds the
         error number to the reply as keyErrorNumber for nonzero
         handler returns.
      */
      
      return theErr;
   }     
   else{  
      if((typeCode == typeChar) || (typeCode == typeStyledText) || 
         (typeCode == typeIntlText)) {
         /*
            If one of these types match, we've been passed a name
            of a resource. Use AEGetParamPtr to move it into our
            string and transform it into a Pascal type string
            that we can pass to GetNamedResource. If we get an
            error in AEGetParamPtr, just let it fall through to
            the bottom of this handler.
         */
      



         theErr = AEGetParamPtr(theAEEvent, keyDirectObject,
                           typeChar, &typeCode, (Ptr)&ourRezName, 
                           sizeof(ourRezName), &actualSize);
                           
         if(theErr == noErr) {
            /* 'C' string has a null as last char */
            ourRezName[actualSize] = '\0';
            /* convert to Pascal string */
            c2pstr((char*) ourRezName);
            /* now grab the 'snd ' resource by name*/
            theSndHandle = GetNamedResource(kSndType, 
                                    (ConstStr255Param)ourRezName);
            /* check the error */
            theErr = ResError();
            if(theErr == noErr)
               theErr = PlaySound(theSndHandle);   /*call our */
                                                   /* sound code*/
         }
      }
      else { 
         if(typeCode == typeLongInteger) {
         
            /* 
               If we get a typeLongInteger, the user wants us to
               play a sound by its resource ID.

               AppleScript will send us a long here and the
               Resource Manager wants us to pass in a short, so
               let's have the Apple Event Manager coerce it to a
               short for us.
            */
            
            theErr = AEGetParamPtr(theAEEvent, keyDirectObject, 
                              typeShortInteger, &typeCode,
                              (Ptr)&ourRezID, sizeof(ourRezID), 
                              &actualSize);
            if(theErr == noErr) {
               /* now grab the 'snd ' resource by ID */
               theSndHandle = GetResource (kSndType, ourRezID);
               /* check the error */
               theErr = ResError();
               if(theErr == noErr)
                  theErr = PlaySound(theSndHandle); /*call our */
                                                    /* sound code*/
            }
         }
         else  {
            if(typeCode == typeAlias) {
               
               /* 
                  If we receive a typeAlias, the user is asking us
                  to play a sound file. We want to use a FSSpec to 
                  open the resource file, so once again we ask the
                  Apple Event Manager to coerce data to the type
                  we need.
               */
               
               theErr = AEGetParamPtr(theAEEvent, keyDirectObject, 
                              typeFSS, &typeCode,
                              (Ptr)&ourSoundFile,
                              sizeof(ourSoundFile), 
                              &actualSize);
               if(theErr != noErr)
                  return theErr;
                  /* save off our current resource file */
               curResFile = CurResFile();
               
               /* open our resource file  for reading */
               ourFileRef = FSpOpenResFile(&ourSoundFile,
                  fsRdPerm);
               
               /* check the error */
               theErr = ResError();
               if(theErr != noErr)
                  return theErr;
                  
               /* make our files resource fork top in the chain */
               UseResFile(ourFileRef);
               
               /* 
                  Since we don't know for sure the resource id of
                  the targeted files 'snd ' resource, let's just
                  get the first (and supposedly only) one.
               */
               
               theSndHandle = Get1IndResource(kSndType, 1); 
               
               /* check the error */
               theErr = ResError();
               if(theErr == noErr) 
                  theErr = PlaySound(theSndHandle);
               
               /* restore resource chain and close our file */
               UseResFile(curResFile);
               CloseResFile(ourFileRef);
            }
            else /* wasn't a string, alias, or number so exit */
               return errAEEventNotHandled;
         }
      }
   } 
   /* dispose 'snd ' handle if necessary */
   if(theSndHandle != nil) ReleaseResource(theSndHandle);
   
   return theErr;
}
 //////////////////////////////////////////////////////////////////// 
//
// PlaySound(Handle theSoundHdl) 
//
// This is the code to play a 'snd '. 
//
//////////////////////////////////////////////////////////////////

OSErr PlaySound(Handle theSoundHdl) 
 {
   /* our variables */
   OSErr    theErr = noErr;
   SndChannelPtr theSndChan = NULL; /*NULL pointer to a */
                                    /* sound channel*/
   
   /* open a channel so we can do synchronous play */
   theErr = SndNewChannel (&theSndChan, sampledSynth,
                   initMono, NULL);
   
   if (theErr == noErr) /* play that sound */
      theErr = SndPlay (theSndChan, theSoundHdl, !kAsync);

   /* dispose of the channel, if the sound channel was allocated */
   if (theSndChan != NULL)
      SndDisposeChannel(theSndChan, !kQuietNow);
   
   return theErr;
 }






/**********************************************
   
   Resource file for PlaySnd.c
   Copyright ®1993 Apple Computer Inc.
   All rights reserved.
   Written by Donald Olson
         
***********************************************/ 

#include "Types.r"#include "SysTypes.r"#include "AEUserTermTypes.r"
/* our version 1 and 2 resources */
resource 'vers' (1) {
   0x1,
   0x0,
   final,
   0x0,
   verUS,
   "1.0",
   "1.0, Copyright ® 1993 Apple Comput"   "er, Inc. All rights reserved."};

resource 'vers' (2) {
   0x1,
   0x0,
   final,
   0x0,
   verUS,
   "1.0",
   "(by Donald Olson)"};

/* 
   This string is used when the user double-clicks on a scripting
   addition file. Since it contains nothing that can be opened or 
   printed, the user gets this in a dialog box (thanks to the
   system for making this happen).
*/

resource 'STR ' (-16397) {
   "This document can not be opened or printed."   " It extends the functionality of AppleScript(TM) "   "and should be placed in the Scripting Additions"   "folder found in the Extensions folder of your"   " System Folder."};

/*
   Our 'aete' resource. It's here that we describe to 
   AppleScript the syntax of our scripting addition. Notice that 
   the comment field contains information about the event and
   its parameters. These comments can be displayed by the
   Script Editor if the user selects this scripting addition in 
   the terminology browser invoked when the user chooses the 
   Open Dictionary menu.
*/

resource 'aete' (0, "Play Sound scripting addition") {
   0x0,
   -0x70,
   english,
   roman,
   {  /* array Suites: 1 elements */
      /* [1] */
      "System Object Suite",
      "",
      'syso',
      1,
      1,
      {  /* array Events: 1 elements */
         /* [1] */
         "play sound",
         " This is the syntax for invoking this scripting"         " addition from AppleScript(TM).",
         'aevt',
         'plsn',
         noReply,
         "The reply is not required",
         replyOptional,
         singleItem,
         notEnumerated,
         reserved,
         reserved,
         reserved,
         reserved,
         reserved,
         reserved,
         reserved,
         reserved,
         reserved,
         reserved,
         reserved,
         reserved,
         reserved,
         '****',
         "id or name of 'snd ' resource to play"         " or  path to a sound file",
         directParamRequired,
         singleItem,
         notEnumerated,
         doesntChangeState,
         reserved,
         reserved,
         reserved,
         reserved,
         reserved,
         reserved,
         reserved,
         reserved,
         reserved,
         reserved,
         reserved,
         reserved,
         {  /* array OtherParams: 0 elements */
         }
      },
      {  /* array Classes: 0 elements */
      },
      {  /* array ComparisonOps: 0 elements */
      },
      {  /* array Enumerations: 0 elements */
      }
   }
};


Previous Book Contents Book Index Next
© Apple Computer, Inc.
18 DEC 1996